<?php

/*
/*  vim:ts=4:expandtab:cindent
 *  This file is part of Urd.
 *
 *  Urd is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 3 of the License, or
 *  (at your option) any later version.
 *  Urd is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program. See the file "COPYING". If it does not
 *  exist, see <http://www.gnu.org/licenses/>.
 *
 * $LastChangedDate: 2008-12-05 23:44:23 +0100 (Fri, 05 Dec 2008) $
 * $Rev: 321 $
 * $Author: gavinspearhead $
 * $Id: urdd_config.php 321 2008-12-05 22:44:23Z gavinspearhead $
 */

// This is an include-only file:
 if (!defined('ORIGINAL_PAGE')) die('This file cannot be accessed directly.');

$pathu = realpath(dirname(__FILE__));
require_once "$pathu/../functions/urdversion.php";
require_once "$pathu/../functions/autoincludes.php";
require_once "$pathu/../functions/defines.php";
require_once "$pathu/../config.php";
require_once "$pathu/../functions/functions.php";
require_once "$pathu/../functions/urd_log.php";
require_once "$pathu/urdd_error.php";


function verify_bool($entry, array $config)
{
    if (!is_bool($config[$entry]))
        throw new exception("Boolean value required for $entry", ERR_CONFIG_ERROR);
}


function verify_isnumeric($entry,  array $config)
{
    if (!is_numeric($config[$entry]))
        throw new exception("Numeric value required for $entry {$config[$entry]}", ERR_CONFIG_ERROR);
}


function verify_path(DatabaseConnection $db, $path, test_result_list &$test_results)
{
    echo_debug_function(DEBUG_SERVER, __FUNCTION__);
    assert($path != '');
    if (strpos($path, '..') !== FALSE) // we don't want relative paths (maybe slightly too tight tho)
        throw new exception('Invalid directory: '. $path, ERR_CONFIG_ERROR);

    clearstatcache(); // we want to be sure, so cache values are flushed.
    if (substr($path, -1) != '/') // add / if necessary
        $path .= '/';

    if (!file_exists($path)) { // check if the path exists
        $rv = @mkdir($path, 0775, TRUE); // if not make it (set the group rights to rwx because we use the group mostly)
        if (!$rv) 
            throw new exception('Cannot create download path: ' . $path, ERR_CONFIG_ERROR);
        set_group($db, $path); // set the group from the config
        clearstatcache(); // we want to be sure, so cache values are flushed.
        if ((!is_dir($path) || !is_writable($path))) // check if the just created path is writable
            throw new exception('Cannot create download path: ' . $path, ERR_CONFIG_ERROR);
    }
    else if (!is_dir($path) || !is_writable($path))  // if it exist, check if it is a dir and if it is writable
        throw new exception ('Download path not set correctly: ' . $path, ERR_CONFIG_ERROR);

    $paths = get_all_paths($path); // get the main paths needed  (tmp, done, preview)
    foreach ($paths as $p) {
        if (!file_exists($p)) {
            $rv = create_dir($p, 0775); // and create the paths if they exist
            if ($rv === FALSE)
                throw new exception("Could not create directory $p", ERR_CONFIG_ERROR);
            set_group($db, $p); // change the group if config is set
        }
        clearstatcache(); // we want to be sure, so cache values are flushed.
        if ((!is_dir($p) || !is_writable($p))) // check if it valid now
            throw new exception("Directory not accessible: $p", ERR_CONFIG_ERROR);
        test_file_creation($p);
        create_required_user_dirs($db, $p);

        $test_results->add(new test_result('Directory '. $p, TRUE, 'Directory usable'));
    }

    return $path;
}


function verify_memory_limit(test_result_list &$test_results)
{
    $memory_size = unformat_size(ini_get('memory_limit'));
    if ($memory_size < (128 * 1024 * 1024)) {
        write_log('Memory limit should be set to at least 128M in ' . php_ini_loaded_file(), LOG_WARNING);
        $test_results->add(new test_result('Memory limit', FALSE, 'Memory limit below 128M'));
    }
    $test_results->add(new test_result('Memory limit', TRUE, 'Memory limit above 128M'));
}


function verify_magpie_cache_dir(test_result_list &$test_results)
{
    $path = get_magpie_cache_dir();
    clearstatcache(); // we want to be sure, so cache values are flushed.
    if (!file_exists($path)) {
        $rv = @mkdir($path, 0775, TRUE);
        set_group($db, $path);
        if (!$rv) 
            throw new exception('Cannot create Magpie cache directory: ' . $path, ERR_CONFIG_ERROR);
    }
    else if (!is_dir($path) || !is_writable($path)) 
        throw new exception ('Magpie cache directory not set correctly: ' . $path, ERR_CONFIG_ERROR);
    $test_results->add(new test_result('Magpie Cache dir', TRUE, 'Magpie directory accessable'));
    return $path;
}



function verify_config(DatabaseConnection $db, test_result_list &$test_results)
{
    global $config, $log_str;
    
    check_prefs($db);
    $prefs = load_config($db);
    $dlpath = get_dlpath($db);

    verify_path($db, $dlpath, $test_results);

    /* verify parameters we have */
    verify_isnumeric('urdd_maxthreads', $prefs);
    verify_isnumeric('urdd_port', $config);
    verify_isnumeric('urdd_port', $prefs);
    verify_isnumeric('urdd_timeout', $config);
    verify_isnumeric('urdd_queue_size', $config);
    verify_isnumeric('default_expire_time', $prefs);
    verify_isnumeric('maxmsgs', $config);

    if (!isset($config['urdd_restart']) || !is_bool($config['urdd_restart'])) 
        $config['urdd_restart'] = $prefs['urdd_restart'] == 1 ? TRUE:FALSE;

    try {
        $scheduler = get_config($db, 'scheduler');
        $config['scheduler'] = $scheduler == 'off' ? FALSE : TRUE;
    } catch (exception $e) {
        // just keep the default
    }

    if (!isset($config['check_nntp_connections'])) {
        if (isset($prefs['check_nntp_connections']))
            $config['check_nntp_connections']= $prefs['check_nntp_connections'];
        else 
            $config['check_nntp_connections'] = 1;
    }

    if (isset($config['find_servers']) && $config['find_servers'] === TRUE) {
        $config['check_nntp_connections'] = FALSE;
    }
    try {
        $log_level = get_config($db, 'log_level');
        if (isset($log_str[$log_level]))
            $config['urdd_min_loglevel'] = $log_level;
        else
            ;//  just keep the default
    } catch (exception $e) {
        // just keep the default
    }
    
    if (!isset($config['update_disable_keys'])|| !is_bool($config['update_disable_keys'])) // do we disable keys when running updates
        $config['update_disable_keys'] = TRUE; 

    /* verify other tools we may need -- rewrite as we do use the db now to store them verify before saving prefs*/
    verify_tool($db, 'urdd', FALSE);
    verify_tool($db, 'yydecode', FALSE);
    verify_tool($db, 'cksfv', TRUE);
    verify_tool($db, 'unpar', TRUE);
    verify_tool($db, 'unrar', TRUE);
    verify_tool($db, 'unarj', TRUE);
    verify_tool($db, 'unace', TRUE);
    verify_tool($db, 'un7zr', TRUE);
    verify_tool($db, 'unzip', TRUE);
    verify_tool($db, 'file', TRUE);
    verify_tool($db, 'trickle', TRUE);
    verify_tool($db, 'tar', TRUE);
    verify_tool($db, 'cksfv', TRUE);

    $config['urdd_listen_host'] = trim($config['urdd_listen_host']);
    $config['urdd_listen_host6'] = trim($config['urdd_listen_host6']);
    if ($config['urdd_listen_host'] == '' && $config['urdd_listen_host6'] == '') 
        throw new exception ('No listening host specified', ERR_CONFIG_ERROR);
}


function verify_tool(DatabaseConnection $db, $toolname, $optional=FALSE)
{
    $path = get_config($db, "{$toolname}_path" );
    if (!$optional && $path == '')
	    $rv = FALSE;
    else if ($path != '' && !is_executable($path)) 
	    $rv = FALSE;
    else 
	    $rv = TRUE;
    if (!$rv)
         throw new exception ("File not found ($toolname) $path. Check admin/config", ERR_CONFIG_ERROR);
}


class module
{
    public $name;
    public $optional;
    function __construct ($name_, $optional_) 
    {
        assert(is_bool($optional_));
        $this->name = $name_;
        $this->optional = $optional_;
    }
}


$modules = array (
    new module('curl', FALSE),
    new module('openssl', TRUE),
    new module('pcntl', FALSE),
    new module('pcre', FALSE),
    new module('posix', FALSE),
    new module('sockets', FALSE),
    new module('SPL', FALSE),
    new module('xmlrpc', TRUE),
    new module('gmp', FALSE),
    new module('xmlreader', TRUE),
    new module('xmlwriter', TRUE)
);


function check_modules(test_result_list &$test_results)
{
    echo_debug_function(DEBUG_SERVER, __FUNCTION__);
    global $modules;
    $error = 0;
    foreach ($modules as $mod) {
        if (!extension_loaded($mod->name)) {
            if ($mod->optional) {
                write_log("Optional PHP module not loaded :{$mod->name}. Not all functions may be working", LOG_WARNING);
                $test_results->add(new test_result("Optional module {$mod->name}", FALSE, "Optional PHP module not loaded :{$mod->name}"));
            } else {
                write_log("Required PHP module not loaded :{$mod->name}.", LOG_ERR);
                $test_results->add(new test_result("Required module {$mod->name}", FALSE, "Required PHP module not loaded :{$mod->name}"));
                $error++;
            }
        } else 
            $test_results->add(new test_result(($mod->optional? 'Optional': 'Required') . " module {$mod->name}", TRUE, ($mod->optional? 'Optional': 'Required') . " PHP module loaded :{$mod->name}"));
    }
    if ($error > 0)
        throw new exception ('Not all required modules have been loaded', ERR_CONFIG_ERROR);
    check_xml_function($test_results);
}


function check_xml_function(test_result_list &$test_results)
{
    if (!function_exists('xml_parser_create')) {
        $test_results->add(new test_result('xml_parser_create', FALSE, 'Not all required modules have been loaded'));
        throw new exception ('Not all required modules have been loaded', ERR_CONFIG_ERROR);
    } else 
        $test_results->add(new test_result('xml_parser_create', TRUE, 'Required modules has been loaded'));
}


function check_pid_file($pid_file)
{
    if (file_exists($pid_file)) {
        $pid = file_get_contents($pid_file);
        if (is_numeric($pid) && $pid > 0) {
            $oldErrorLevel = error_reporting(0);
            $prio = pcntl_getpriority($pid);
            error_reporting($oldErrorLevel);
            if ($prio !== FALSE)
                throw new exception("An instance of URDD seems already been running with pid: $pid", ERR_ALREADY_RUNNING);
            else 
                delete_pid_file($pid_file);
        } else 
            throw new exception('There seems to be something wrong with the PID file ' . $pid_file . ".\nPlease remove this file first", ERR_ALREADY_RUNNING);
    } else 
        return TRUE;
}


function set_pid_file($pid_file)
{
    $pid = posix_getpid();
    if (FALSE === file_put_contents($pid_file, $pid))
        throw new exception('Cannot write pid file '. $pid_file);
}


function delete_pid_file($pid_file)
{
    if (file_exists($pid_file)) 
        @unlink($pid_file);
}
    

function set_db_version(DatabaseConnection $db)
{
    $ver = get_config($db, 'URD_version');
    $ver2 = get_version();
    if (version_compare($ver, $ver2, '<') === TRUE)
        set_config($db, 'URD_version', $ver2);
}


function test_urdland_connection(DatabaseConnection $db, test_result_list &$test_results)
{
    global $config;
    if (isset($config['connect_urdland']) && $config['connect_urdland'] !== TRUE)
        return FALSE;

    $prefs = load_config($db);
    $u = $prefs['forumusername'];
    $p = $prefs['forumpassword'];
    if ($u == '' || $p == ''){
        $test_results->add(new test_result('urdland', FALSE, 'No URDLand account provided. Extra set info cannot be received'));
        return FALSE;
    }
    $userinfo = array($u, $p);
    $params = array($userinfo, array());

    $result = XMLRPC_to_URD_central_server('GetSetInfo', $params);
    if ($result === FALSE) {
        $test_results->add(new test_result('urdland', FALSE, 'Connection to URDLAND failed. Extra set info may not be received'));
        write_log('Connection to URDLAND failed. Extra set info may not be received', LOG_ERR);
    } else 
        $test_results->add(new test_result('urdland', TRUE, 'Connection to URDLAND successful'));
}


?>
